﻿using HCMS.CommonDtos;
using HCMS.Const;
using HCMS.DomainServiceManage.Cache.Manage;
using HCMS.Entities.Manage;
using HCMS.Extensions;
using HCMS.IRepositories.Manage;
using HCMS.IServices.Manage;
using HCMS.Repositories.Manage;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;

namespace HCMS.Services.Manage
{
    /// <summary>
    /// 角色 菜单 应用服务
    /// </summary>
    public class RoleMenuAppService : CommonAppService<ManageDbContext, RoleMenu>, IRoleMenuAppService
    {
        private readonly IRepository<RoleMenu> baseRoleMenuRepository;
        private readonly IRoleMenuRepository roleMenuRepository;
        private readonly IMenuRepository menuRepository;
        private readonly IRoleRepository roleRepository;
        private readonly RoleMenuCacheManager roleMenuCacheManager;

        public RoleMenuAppService(
            IRepository<RoleMenu> baseRoleMenuRepository,
            IRoleMenuRepository roleMenuRepository,
            IMenuRepository menuRepository,
            IRoleRepository roleRepository,
            RoleMenuCacheManager roleMenuCacheManager
            ) : base(baseRoleMenuRepository)
        {
            this.baseRoleMenuRepository = baseRoleMenuRepository;
            this.roleMenuRepository = roleMenuRepository;
            this.menuRepository = menuRepository;
            this.roleRepository = roleRepository;
            this.roleMenuCacheManager = roleMenuCacheManager;
        }

        /// <summary>
        /// 设置角色 菜单权限
        /// </summary>
        /// <param name="roleId">角色 Id</param>
        /// <param name="menuId">菜单 Id 列表</param>
        /// <param name="updateUser">更新 人</param>
        /// <returns></returns>
        public async Task<bool> SetRoleMenu(int roleId, List<int> menuId, string updateUser)
        {
            // 删除原来的
            var oldMenuList = (await GetAllAsync())?.Where(t => t.RoleId == roleId && t.Status == 0)?.ToList();
            if (oldMenuList != null && oldMenuList.Any())
            {
                foreach (var item in oldMenuList)
                {
                    item.Status = -1;
                    item.UpdateTime = DateTime.Now;
                    item.UpdateUser = updateUser;

                    await BaseUpdateAsync(item);
                }
            }

            // 写入本次的菜单信息
            if (menuId != null && menuId.Count > 0)
            {
                foreach (var item in menuId)
                {
                    var roleMenu = new RoleMenu()
                    {
                        RoleId = roleId,
                        MenuId = item,
                        CreateTime = DateTime.Now,
                        CreateUser = updateUser,
                        UpdateTime = DateTime.Now,
                        UpdateUser = updateUser,
                        Status = 0
                    };

                    await BaseInsertAsync(roleMenu);
                }
            }

            return true;
        }

        /// <summary>
        /// 根据角色 Id 获取已选中菜单 Ids
        /// </summary>
        /// <param name="roleId">角色 Id</param>
        /// <returns></returns>
        public async Task<List<int>> GetSelectMenuIdByRoleId(int roleId)
        {
            var result = new List<int>();
            if (roleId == ManageConst.SuperRoleId)
            {
                result = (await menuRepository.GetQueryableAsync())?.ToListAsync()?.Result?.Where(t => t.Status == 0)?.Select(t => t.Id).ToList();
            }
            else
            {
                result = (await GetAllAsync())?.Where(t => t.RoleId == roleId && t.Status == 0)?.Select(t => t.MenuId).ToList();
            }

            return result ?? new List<int>();
        }

        /// <summary>
        /// 根据角色 Id 获取菜单列表
        /// </summary>
        /// <param name="roleId">角色 Id</param>
        /// <param name="isRefreshCache">是否刷新缓存</param>
        /// <returns></returns>
        public async Task<List<Menu>> MenuListByRoleId(int roleId, bool isRefreshCache = false)
        {
            if (!isRefreshCache)
            {
                var cacheValue = await roleMenuCacheManager.GetMenuList(roleId);
                if (cacheValue != null && cacheValue.Any())
                {
                    return cacheValue;
                }
            }

            var menuIdList = await GetSelectMenuIdByRoleId(roleId);
            var result = await menuRepository.GetMenuListByIds(menuIdList);
            if (result != null && result.Any())
            {
                await roleMenuCacheManager.SetMenuList(roleId, result);
            }

            return result ?? new List<Menu>();
        }

        /// <summary>
        /// 根据 角色 Id 获取管理系统菜单
        /// </summary>
        /// <param name="roleId">角色 Id</param>
        /// <param name="isRefreshCache">是否刷新缓存</param>
        /// <returns></returns>
        public async Task<List<ManageMenuTreeDto>> GetManageMenuByRoleId(int roleId, bool isRefreshCache = false)
        {
            if (!isRefreshCache)
            {
                var cacheValue = await roleMenuCacheManager.GetManageMenu(roleId);
                if (cacheValue != null && cacheValue.Any())
                {
                    return cacheValue;
                }
            }

            var menus = await MenuListByRoleId(roleId, isRefreshCache);
            var menuIdList = menus.Select(t => t.Id).ToList();
            var result = await menuRepository.GetManageMenuTree(menuIdList);
            if (result != null)
            {
                await roleMenuCacheManager.SetManageMenu(roleId, result);
            }

            return result ?? new List<ManageMenuTreeDto>();
        }

        /// <summary>
        /// 根据 角色 Id 刷新缓存
        /// </summary>
        /// <param name="roleId">角色 Id</param>
        /// <returns></returns>
        public async Task<bool> RefreshCacheByRoleId(int roleId)
        {
            await GetManageMenuByRoleId(roleId, true);
            return true;
        }

        /// <summary>
        /// 查找角色指定权限
        /// </summary>
        /// <param name="roleId">角色 Id</param>
        /// <param name="findControllerName">权限所在的控制器名称</param>
        /// <param name="actionNames">需要生成的方法名称</param>
        /// <returns></returns>
        public async Task<List<Menu>> FindMenuByRole(int roleId, string findControllerName, string[] actionNames)
        {
            if (roleId <= 0 || string.IsNullOrWhiteSpace(findControllerName) || actionNames == null || actionNames.Length == 0)
            {
                return new List<Menu>();
            }

            if (roleId != ManageConst.SuperRoleId)
            {
                var role = await roleRepository.FirstOrDefaultAsync(t => t.Id == roleId);
                if (role == null || role.Status != 0)
                {
                    return new List<Menu>();
                }
            }

            var menus = await MenuListByRoleId(roleId);
            if (menus == null || !menus.Any())
            {
                return new List<Menu>();
            }

            var result = menus.Where(t => t.ControllerName.IsSame(findControllerName) && actionNames.Contains(t.ActionName, StringComparer.CurrentCultureIgnoreCase))?.ToList();
            return result ?? new List<Menu>();
        }
    }
}
